# SPDX-License-Identifier: GPL-2.0-or-later

'''
RNA Manual Reference Mapping Updater

This script generates a file that maps RNA strings to online URL's
for the context menu documentation access.

This script either downloads a sphinx requirement file from the manual
or optionally can take a path to the file using `--input`.

To make international, we made a script,
pointing the manuals to the proper language,
specified in the 'User Preferences Window' by the users.
Some Languages have their manual page, using a prefix or
being preceded by their respective reference, for example:

manual/ --> manual/ru/

The table in the script, contains all of the languages we have in the
Blender manual website, for those other languages that still
does not have a team of translators,
and/or don't have a manual for their languages we commented the lines below,
you should add them to the language table when they have a proper manual,
or added to the Blender UI  translation table.

URL is the: url_manual_prefix + url_manual_mapping[#id]
'''

import os
import argparse
import re
import sys

try:
    import sphobjinv
except ImportError:
    print("The module \"sphobjinv\" was not found, it may be installed via \"pip install sphobjinv\", exiting!")
    sys.exit(1)

# The root of Blender's source directory.
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "..")

# Names that don't match this regex can't be used as URL's.
re_name_sanity_match = re.compile("[a-zA-Z0-9._*]+")


def sphobjinv_sanity_check(o):
    """
    Ensure ``o`` can be used to make a URL.
    """
    name = o.name
    # Perhaps other characters could be excluded too.
    if not re_name_sanity_match.fullmatch(name):
        m = re_name_sanity_match.match(name)
        fail_char = 0
        if m:
            fail_char = m.span(0)[1]
        msg = "WARNING: invalid char found for name:"
        print(msg, name, "(at index %d)" % fail_char, "skipping!")
        print(" " * (len(msg) + fail_char), "^")
        return False

    if " " in name or "/" in name:
        return False
    return True


def write_mappings(inv, output):
    print("Writing...")
    # Write the file
    file = open(output, "w", encoding="utf-8")
    fw = file.write

    fw("# SPDX-License-Identifier: GPL-2.0-or-later\n")
    fw("# Do not edit this file.")
    fw(" This file is auto generated from rna_manual_reference_updater.py\n\n")
    # Prevent systems with autopep8 configured from re-formatting the file.
    fw("# autopep8: off\n")

    fw(
        "import bpy\n"
        "\n"
        "url_manual_prefix = \"https://docs.blender.org/manual/%s/%d.%d/\" % (\n"
        "    bpy.utils.manual_language_code(),\n"
        "    *bpy.app.version[:2],\n"
        ")\n"
        "\n"
    )

    fw("url_manual_mapping = (\n")



    # Logic to manipulate strings from objects.inv
    lines = [
        o.data_line() for o in inv.objects
        if o.name.startswith(("bpy.types", "bpy.ops"))
        if sphobjinv_sanity_check(o)
    ]
    # Finding first space will return length of rna path
    lines.sort(key=lambda l: l.find(" "), reverse=True)
    for line in lines:
        split = line.split(" ")
        fw("    (\"" + split[0] + "*\", \"" + split[3] + "\"),\n")

    fw(")\n\n")
    fw("# autopep8: on\n")


def is_valid_file(parser, arg):
    if not os.path.isfile(arg):
        parser.error("The file %s does not exist!" % arg)
    else:
        return arg


def main():
    parser = argparse.ArgumentParser(
        usage=__doc__
    )

    parser.add_argument(
        "--input",
        dest="filename",
        required=False,
        help="sphinx inventory file (objects.inv)",
        metavar="FILE",
        type=lambda x: is_valid_file(parser, x))

    parser.add_argument(
        "--output",
        dest="output",
        default=os.path.join(BASE_DIR, "release", "scripts", "modules", "rna_manual_reference.py"),
        required=False,
        help="path to output including filename and extentsion",
        metavar="FILE")

    parser.add_argument(
        "--url",
        dest="url",
        default="https://docs.blender.org/manual/en/dev/objects.inv",
        required=False,
        help="url to sphinx inventory file (objects.inv)",
        metavar="FILE")

    args = parser.parse_args()

    if args.filename:
        # Download and decode objects.inv
        print("Loading from file...")
        inv = sphobjinv.Inventory(args.filename)
    else:
        # Load and decode objects.inv
        print("Downloading...")
        inv = sphobjinv.Inventory(url=args.url)

    write_mappings(inv, args.output)
    print("Done!")


if __name__ == "__main__":
    main()
